/*
Title:      	AltFontPrev
Author:     	Sam Rayner
More Info: 		http://samrayner.com/archives/altfontprev/
*/

var Details = {
  version: "1.1",
  releaseDate: "29th October 08"
}

var Core = {
  snatchClass: function(target, theClass, altClass) {
    var siblings = target.parentNode.childNodes;
    
    for(var i = 0; i < siblings.length; i++) {
       siblings[i].className = altClass;
    }
    
    target.className = theClass;
  }
}

var DOM = {
  elm: function(element) {
    return document.createElement(element);
  },

  id: function(suffix) {
    return document.getElementById("afp-" + suffix);
  }
}

var CSS = {
  fonts: [],
  sels: [],
  
  get: function() {    
    var selNum = 0;
    
    for(var i = 0; i < document.styleSheets.length; i++) {
      for(var j = 0; j < document.styleSheets[i].cssRules.length; j++) {
        var fontFam = document.styleSheets[i].cssRules[j].style.fontFamily;
      
        if(fontFam) {
          CSS.sels[selNum] = document.styleSheets[i].cssRules[j].selectorText;
          var indFonts = fontFam.split(",");
          CSS.fonts[selNum] = new Array(indFonts.length - 1);
          
          for(var fontNum = 0; fontNum < indFonts.length; fontNum++) {
            indFonts[fontNum] = indFonts[fontNum].replace(/^\s+|'+|"+|\s+$|"+$|'+$/g,"");
            CSS.fonts[selNum][fontNum] = indFonts[fontNum].toLowerCase();
          }
          selNum++;
        }
      }
    }
  }
}

var HTML = {
  cssLink: function() {
    var linkElm = DOM.elm("link");
    linkElm.id = "afp-css";
    linkElm.rel = "stylesheet";
    linkElm.type = "text/css";
    linkElm.href = "../afp.css";
    document.getElementsByTagName("head")[0].appendChild(linkElm);
  },
  
  emptyStyle: function() {
    var styleElm = DOM.elm("style");
    styleElm.id = "afp-fontrules";
    styleElm.type = "text/css";
    document.getElementsByTagName("head")[0].appendChild(styleElm);
  },
  
  afpCode: function() {
    var divElm = DOM.elm("div");
	divElm.id = "afp-pane";
	
	divElm.innerHTML = [
	'<p id="afp-title"><span></span>AltFontPrev</p>',
	'<form><label for="selector">Selector:</label>',
	'<select name="selector" id="afp-selectors"></select>',
	'</form><ul id="afp-fontlists"></ul>',
	'<form id="afp-custom"><label for="afp-input">Custom:</label><input id="afp-input" type="search" value="Custom Font"></input></form>',
	'<img id="afp-closeicon" src="http://files.samrayner.com/scripts/altfontprev/images/close.png" width="13" height="13" alt="Close" title="Close" />',
	'<img id="afp-infoicon" src="http://files.samrayner.com/scripts/altfontprev/images/info.png" width="13" height="13" alt="Info" title="Info" />',
	'<div id="afp-info" class="afp-hide"><span></span>',
	'<p>v.' + Details.version + '<em>(' + Details.releaseDate + ')</em></p>',
	'<p>Created by <a target="_blank" href="http://samrayner.com/">Sam Rayner</a></p><p><a target="_blank" href="http://samrayner.com/archives/altfontprev/">More Info&hellip;</a></p></div></div>'
	].join('');
	
	document.getElementsByTagName("body")[0].appendChild(divElm);
  },
  
  selDropdown: function(dest) {
    for(var selNum = 0; selNum < CSS.sels.length; selNum++) {
      var optionElm = DOM.elm("option"); 
      var optionText = document.createTextNode(CSS.sels[selNum]);
      DOM.id(dest).appendChild(optionElm);
      DOM.id(dest).lastChild.appendChild(optionText);
    }
  },
  
  fontLists: function(dest) {
    for(var selNum = 0; selNum < CSS.sels.length; selNum++) {
      var outerLiElm = DOM.elm("li");
      var olElm = DOM.elm("ol");
      DOM.id(dest).appendChild(outerLiElm);
      DOM.id(dest).lastChild.appendChild(olElm); 
    
      for(var fontNum = 0; fontNum < CSS.fonts[selNum].length; fontNum++) {
        var innerLiElm = DOM.elm("li");    
        innerLiElm.style.fontFamily = CSS.fonts[selNum][fontNum] + ",helvetica";
      
        var aElm = DOM.elm("a");
    	aElm.href = "#" + CSS.fonts[selNum][fontNum].replace(/[\s]/g,"_");
      
        if(fontNum % 2 == 0) {
          aElm.className = "afp-stripe";
        }
        
        var fontName = CSS.fonts[selNum][fontNum];

        if(fontName == "serif" 
           || fontName == "sans-serif" 
           || fontName == "cursive" 
           || fontName == "fantasy" 
           || fontName == "monospace") {
          fontName = "default " + fontName;
        }
        
        var spanElm = DOM.elm("span"); 
        spanElm.style.fontFamily = CSS.fonts[selNum][fontNum] + ",wingdings,impact"
        
        var aText = document.createTextNode(fontName);
        var spanText = document.createTextNode("O");
        
        DOM.id(dest).lastChild.lastChild.appendChild(innerLiElm);
        DOM.id(dest).lastChild.lastChild.lastChild.appendChild(aElm);
        DOM.id(dest).lastChild.lastChild.lastChild.lastChild.appendChild(aText);
        DOM.id(dest).lastChild.lastChild.lastChild.lastChild.appendChild(spanElm);
        DOM.id(dest).lastChild.lastChild.lastChild.lastChild.lastChild.appendChild(spanText);
      }
    }
  },
  
  error: function() {
    DOM.id("selectors").disabled = true;
    DOM.id("input").disabled = true;
    
    var optionElm = DOM.elm("option"); 
    optionText = document.createTextNode("Uh oh.");
    
    DOM.id("selectors").appendChild(optionElm);
    DOM.id("selectors").lastChild.appendChild(optionText);
    
    var liElm = DOM.elm("li");
    liElm.id = "afp-error";
    
    var liText = document.createTextNode("Looks like there are no fonts declared...");
    
    DOM.id("fontlists").appendChild(liElm);
    DOM.id("fontlists").lastChild.appendChild(liText);
  },
  
  customFont: function(fontName) {
    var selIndex = DOM.id("selectors").selectedIndex;
    var fontList = DOM.id("fontlists").childNodes[selIndex].firstChild;
    
    var liElm = DOM.elm("li");    
    liElm.id = "afp-customfont";
    liElm.style.fontFamily = fontName.toLowerCase() + ",helvetica";
      
    var aElm = document.createElement("a");
    aElm.className = "afp-stripe";
    aElm.href = "#" + fontName.replace(/[\s]/g,"_");
    
    var spanElm = document.createElement("span"); 
    spanElm.style.fontFamily = fontName.toLowerCase() + ",wingdings,impact";
        
    var aText = document.createTextNode(fontName);
    var spanText = document.createTextNode("O");
    
    if(DOM.id("customfont")) {
      DOM.id("customfont").parentNode.removeChild(DOM.id("customfont"));
    }
    
    DOM.id("custom").className = "afp-active";
    fontList.appendChild(liElm);
    fontList.lastChild.appendChild(aElm);
    fontList.lastChild.lastChild.appendChild(aText);
    fontList.lastChild.lastChild.appendChild(spanElm);
    fontList.lastChild.lastChild.lastChild.appendChild(spanText);
  }
}

// Huge thankyou to Aaron Boodman for this fantastic bit of code. 
// The Drag object that follows is all Aaron's work. I claim no credit for it.
// You can find it at: http://youngpup.net/projects/dom-drag/
// ---------------------------------------------------------------------------

var Drag = {
  obj : null,

  init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper) {
    o.onmousedown = Drag.start;

    o.hmode = bSwapHorzRef ? false : true ;
    o.vmode = bSwapVertRef ? false : true ;

    o.root = oRoot && oRoot != null ? oRoot : o ;

    if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "30px";
    if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "30px";
    if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
    if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

    o.minX	= typeof minX != 'undefined' ? minX : null;
    o.minY	= typeof minY != 'undefined' ? minY : null;
    o.maxX	= typeof maxX != 'undefined' ? maxX : null;
    o.maxY	= typeof maxY != 'undefined' ? maxY : null;

    o.xMapper = fXMapper ? fXMapper : null;
    o.yMapper = fYMapper ? fYMapper : null;

    o.root.onDragStart = new Function();
    o.root.onDragEnd   = new Function();
    o.root.onDrag      = new Function();
  },

  start : function(e) {
    var o = Drag.obj = this;
	e = Drag.fixE(e);
	var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
	var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
	o.root.onDragStart(x, y);

	o.lastMouseX = e.clientX;
	o.lastMouseY = e.clientY;

	if (o.hmode) {
	  if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
	  if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
	} 
	else {
	  if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
	  if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
	}

	if (o.vmode) {
	  if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
	  if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
	} 
	else {
	  if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
	  if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
	}

	document.onmousemove = Drag.drag;
	document.onmouseup	 = Drag.end;

	return false;
  },

  drag : function(e) {
	e = Drag.fixE(e);
	var o = Drag.obj;

	var ey	= e.clientY;
	var ex	= e.clientX;
	var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
	var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
	var nx, ny;

	if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
	if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
	if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
	if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

	nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
	ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

	if (o.xMapper)		nx = o.xMapper(y)
	else if (o.yMapper)	ny = o.yMapper(x)

	Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
	Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
	Drag.obj.lastMouseX	= ex;
	Drag.obj.lastMouseY	= ey;

	Drag.obj.root.onDrag(nx, ny);
	return false;
  },

  end : function() {
	document.onmousemove = null;
	document.onmouseup   = null;
	Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
							parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
	Drag.obj = null;
  },

  fixE : function(e) {
	if (typeof e == 'undefined') e = window.event;
	if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
	if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
	return e;
  }
}

// ---------------------------------------------------------------------------

var Do = {
  showFonts: function(selNum) {
    var selFonts = DOM.id("fontlists").childNodes[selNum];
    Core.snatchClass(selFonts, "afp-show", "afp-hide");
    DOM.id("custom").className = "";
    
    if(DOM.id("customfont")) {
      DOM.id("customfont").parentNode.removeChild(DOM.id("customfont"));
    }
  },

  applyFont: function(selected) {
    Core.snatchClass(selected, "afp-current", "");
    
    var liArray = selected.parentNode.childNodes;
    var selIndex = DOM.id("selectors").selectedIndex;
    
    for(var i = 0; i < liArray.length; i++) {
	  if(liArray[i] == selected) {
	    var fontIndex = i;
	  }
	}

    var newRule = CSS.sels[selIndex] + " {font-family: ";
    
    if(selected.id == "afp-customfont") {
      newRule += DOM.id("input").value;
    }
    else {
      newRule += CSS.fonts[selIndex][fontIndex];
    }
    
    for(var i = 0; i < CSS.fonts[selIndex].length; i++) {
      newRule += "," + CSS.fonts[selIndex][i];
    }
    
    newRule += "}";
    
    var newRuleText = document.createTextNode(newRule);
    DOM.id("fontrules").appendChild(newRuleText);
  }
}

var Action = {
  selSelect: function() {
    Do.showFonts(DOM.id("selectors").selectedIndex);
  },

  fontClick: function() {
    Do.applyFont(this);
  },
  
  customSubmit: function(event) {
    event.preventDefault();
    var pattern = /\S/;
    
    if(pattern.test(DOM.id("input").value)) {
      HTML.customFont(DOM.id("input").value);
      Do.applyFont(DOM.id("customfont"));
	  DOM.id("customfont").addEventListener("click", Action.fontClick, false);
	}
  },
  
  customClear: function() {
    if(DOM.id("input").value == "Custom Font") {
      DOM.id("input").value = "";
    }
  },
  
  customFill: function() {
    if(DOM.id("input").value == "") {
      DOM.id("input").value = "Custom Font";
    }
  },

  closeClick: function() {
    DOM.id("fontrules").parentNode.removeChild(DOM.id("fontrules"));
    DOM.id("css").parentNode.removeChild(DOM.id("css"));
    DOM.id("pane").parentNode.removeChild(DOM.id("pane"));
    DOM.id("js").parentNode.removeChild(DOM.id("js"));
  },
  
  infoClick: function() {
    if(DOM.id("info").className == "afp-hide") {
      DOM.id("info").className = "afp-show";
    }
    else {
      DOM.id("info").className = "afp-hide";
    }
  },
  
  listeners: function() {
    DOM.id("selectors").addEventListener("change", Action.selSelect, false);
    
    for(var i = 0; i < DOM.id("fontlists").childNodes.length; i++) {
      for(var j = 0; j < DOM.id("fontlists").childNodes[i].firstChild.childNodes.length; j++) {
        DOM.id("fontlists").childNodes[i].firstChild.childNodes[j].addEventListener("click", Action.fontClick, false);
      }
    }
    
    DOM.id("custom").addEventListener("submit", Action.customSubmit, false);
    DOM.id("input").addEventListener("focus", Action.customClear, false);
    DOM.id("input").addEventListener("blur", Action.customFill, false);
    DOM.id("closeicon").addEventListener("click", Action.closeClick, false);
    DOM.id("infoicon").addEventListener("click", Action.infoClick, false);
  }
}

var Load = {
  altFontPrev: function() {  
    CSS.get();
    HTML.cssLink();
    HTML.emptyStyle();
    HTML.afpCode();
  
    if(CSS.sels.length > 0) {
      HTML.selDropdown("selectors");
      HTML.fontLists("fontlists");
    }  
    else {
      HTML.error();
    }
  
    Do.showFonts(0);
    Action.listeners();
    
    Drag.init(DOM.id("title"), DOM.id("pane")); //Thanks again Aaron!
  }
}

window.setTimeout(Load.altFontPrev(), 0);